package org.huang.util;

import lombok.Getter;
import lombok.SneakyThrows;
import sun.misc.Unsafe;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;

/**
 * @author hdu_huang
 * @since 2024/1/1
 *
 */
public class UnsafeUtil {

    // @See caffeine UnsafeAccess
    private static final String OPEN_JDK = "theUnsafe";

    @Getter
    public static final Unsafe unsafe;

    //long sizeCtl; 在 4字节Object、int前，字段重排，达到内存利用率 -XX:FieldsAllocationStyle
    private long reorder; //16
    private volatile int sizeCtl;  //SIZE_CTL = 12

    private static final long SIZE_CTL; //此字段的地址

    static {

        unsafe = loadUnsafe(OPEN_JDK);
        SIZE_CTL = getFieldAddress(UnsafeUtil.class, "sizeCtl");
        long c = getFieldAddress(UnsafeUtil.class, "reorder");
    }

    private static Unsafe loadUnsafe(String openJdk) {

        Field field;

        try {
            field = Unsafe.class.getDeclaredField(openJdk);
            field.setAccessible(true);
            return (Unsafe) field.get(null);

        }catch (Exception ignored) {
        }

        return null;
    }

    // 反射相关 ReflectionUtils
    public static Field getField(Class<?> clazz, String fieldName) {

        Field field;
        try {
            field = clazz.getDeclaredField(fieldName);
            field.setAccessible(true);
            return field;

        }catch (Exception ignored) {
        }

        return null;
    }

    public static Object getFieldValue(Field field, Object target) {

        try {
            field.setAccessible(true);
            return field.get(field);

        } catch (Exception ignored) {
        }

        return null;
    }

    public static Object getFieldValue(Object target, String fieldName) {

        try {
            Field field = target.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            return field.get(target);
        } catch (Exception ignored) {
        }
        return null;
    }

    //staticFieldOffset
    public static long getFieldAddress(Class<?> clazz, String fieldName) {
        return unsafe.objectFieldOffset(getField(clazz, fieldName));
    }

    public static long getStaticFieldAddress(Class<?> clazz, String fieldName) {
        return unsafe.staticFieldOffset(getField(clazz, fieldName));
    }

    //throw t; Throwable强转为RuntimeException, 但是因为JVM并不关心这个。泛型最后存储为字节码时并没有泛型的信息。这样写只是为了骗过javac编译器
    //https://www.jianshu.com/p/7d0ed3aef34b
    @SneakyThrows
    public static Object newInstance(Class<?> type) {
        return unsafe.allocateInstance(type);
    }



    // java/javac -X  是JVM参数,不是程序参数
    // exports导出只能访问public   opens可以访问所有[深度反射]
    //! 编译如果使用 --add-exports, 则运行时--add-opens就可以反射和包导入一起使用了, 如果只有反射使用--add-opens就可以了
    // --illegal-access=warn [java] 17取消   深度反射时警告
    //
    //--add-opens java.base/jdk.internal.misc=ALL-UNNAMED   [只是反射, 运行期加此参数就够了]
    //--add-exports java.base/jdk.internal.misc=ALL-UNNAMED   [javac 编译期导出public类]
    //
    //!open和opens都仅仅是开放runtime时期的可以通过反射访问(deep reflection(public及private)
    //!exports  exports表示允许访问指定包的public成员(编译及运行时)
    public static void main(String[] args) throws Exception{

        UnsafeUtil unsafeUtil = new UnsafeUtil();
        unsafeUtil.sizeCtl = 100;

        VarHandle varHandle = MethodHandles.lookup().findVarHandle(UnsafeUtil.class, "sizeCtl", int.class);

        Object o = varHandle.get(unsafeUtil);
        varHandle.setVolatile(unsafeUtil, 123);

        //替代 Unsafe[defineClass, defineAnonymousClass]
        //MethodHandles.lookup().defineClass(null);
        //MethodHandles.lookup().defineHiddenClass(null, false, MethodHandles.Lookup.ClassOption.NESTMATE);

        System.out.println(unsafe.pageSize());
        System.out.println(SIZE_CTL);
        //System.out.println(unsafe.getInt(unsafeUtil, SIZE_CTL));

        unsafe.putIntVolatile(unsafeUtil, SIZE_CTL, 10);
        unsafe.getIntVolatile(unsafeUtil, SIZE_CTL);

        //System.out.println(unsafe.getInt(unsafeUtil, SIZE_CTL));
    }
}
